/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut,
    unused_variables,
    improper_ctypes,
    clippy::never_loop
)]

use crate::check::SUDO_CONV_ERROR_MSG;
//use crate::check::SUDO_CONV_INFO_MSG;
use crate::common::*;
use crate::env::env_init;
use crate::env::env_merge;
use crate::sudoers::sudo_user;
//use crate::check::sudo_defs_types;

pub type size_t = libc::c_ulong;
pub type pam_handle_t = pam_handle;

pub const SUDO_CONV_REPL_MAX: libc::c_int = 255;
pub const SUDO_CONV_INFO_MSG: libc::c_int = 4;
pub const PAM_CONV_ERR: libc::c_int = 19;
pub const PAM_BUF_ERR: libc::c_int = 5;
pub const PAM_MAX_NUM_MSG: libc::c_int = 32;
pub const I_PASSPROMPT_OVERRIDE: libc::c_int = 50;
pub const PAM_SESSION_ERR: libc::c_int = 14;
pub const PAM_DELETE_CRED: libc::c_uint = 4;
pub const MODE_SHELL: libc::c_int = 131072;
pub const PAM_DATA_SILENT: libc::c_int = 1073741824;
pub const PAM_SYSTEM_ERR: libc::c_int = 4;
pub const PAM_SUCCESS: libc::c_int = 0;
pub const AUTH_SUCCESS: libc::c_int = 0;
pub const MODE_LOGIN_SHELL: libc::c_int = 262144;
pub const I_PAM_LOGIN_SERVICE: libc::c_int = 87;
pub const I_PAM_ACCT_MGMT: libc::c_int = 90;
pub const I_PAM_SERVICE: libc::c_int = 86;
pub const I_PAM_SESSION: libc::c_int = 89;
pub const I_PAM_SETCRED: libc::c_int = 88;
pub const AUTH_FATAL: libc::c_int = 3;
pub const PAM_TTY: libc::c_int = 3;
pub const PAM_USER: libc::c_int = 2;
pub const PAM_SILENT: libc::c_uint = 32768;
pub const AUTH_INTR: libc::c_int = 2;
pub const PAM_AUTH_ERR: libc::c_int = 7;
pub const PAM_AUTHINFO_UNAVAIL: libc::c_int = 9;
pub const PAM_MAXTRIES: libc::c_int = 11;
pub const PAM_PERM_DENIED: libc::c_int = 6;
pub const AUTH_FAILURE: libc::c_int = 1;
pub const PAM_NEW_AUTHTOK_REQD: libc::c_int = 12;
pub const PAM_ACCT_EXPIRED: libc::c_int = 13;
pub const PAM_CHANGE_EXPIRED_AUTHTOK: libc::c_int = 32;
pub const PAM_AUTHTOK_EXPIRED: libc::c_int = 27;
pub const PAM_REINITIALIZE_CRED: libc::c_int = 8;

pub const PAM_PROMPT_ECHO_OFF: libc::c_int = 1;
pub const SUDO_CONV_PROMPT_ECHO_ON: libc::c_int = 2;
pub const SUDO_CONV_PROMPT_ECHO_OFF: libc::c_int = 1;
pub const PAM_PROMPT_ECHO_ON: libc::c_int = 2;
pub const PAM_MAX_RESP_SIZE: libc::c_int = 512;

pub const PAM_TEXT_INFO: libc::c_int = 4;
pub const SUDO_CONV_PREFER_TTY: libc::c_int = 8192;
pub const PAM_ERROR_MSG: libc::c_int = 3;

extern "C" {
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
    fn env_get() -> *mut *mut libc::c_char;
    static mut sudo_defs_table: [sudo_defs_types; 0];
    fn pam_close_session(pamh_0: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int;
    fn dcgettext(
        __domainname: *const libc::c_char,
        __msgid: *const libc::c_char,
        __category: libc::c_int,
    ) -> *mut libc::c_char;
    fn strlen(_: *const libc::c_char) -> libc::c_ulong;
    fn sudo_memset_s(v: *mut libc::c_void, smax: size_t, c: libc::c_int, n: size_t) -> libc::c_int;
    fn strncmp(_: *const libc::c_char, _: *const libc::c_char, _: libc::c_ulong) -> libc::c_int;

    fn auth_getpass(
        prompt: *const libc::c_char,
        type_0: libc::c_int,
        callback: *mut sudo_conv_callback,
    ) -> *mut libc::c_char;

    fn calloc(_: libc::c_ulong, _: libc::c_ulong) -> *mut libc::c_void;
    fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn pam_open_session(pamh_0: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int;
    fn pam_getenvlist(pamh_0: *mut pam_handle_t) -> *mut *mut libc::c_char;
    fn strcmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int;
    fn pam_setcred(pamh_0: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int;
    fn pam_end(pamh_0: *mut pam_handle_t, pam_status: libc::c_int) -> libc::c_int;
    fn pam_acct_mgmt(pamh_0: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int;
    fn pam_authenticate(pamh_0: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int;
    fn pam_chauthtok(pamh_0: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int;
    fn strerror(_: libc::c_int) -> *mut libc::c_char;
    fn pam_set_item(
        pamh_0: *mut pam_handle_t,
        item_type: libc::c_int,
        item: *const libc::c_void,
    ) -> libc::c_int;
    fn pam_start(
        service_name: *const libc::c_char,
        user: *const libc::c_char,
        pam_conversation: *const pam_conv,
        pamh_0: *mut *mut pam_handle_t,
    ) -> libc::c_int;
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    fn log_warningx(flags: libc::c_int, fmt: *const libc::c_char, _: ...) -> bool;
    fn __errno_location() -> *mut libc::c_int;
    fn pam_strerror(pamh_0: *mut pam_handle_t, errnum: libc::c_int) -> *const libc::c_char;
    fn snprintf(
        _: *mut libc::c_char,
        _: libc::c_ulong,
        _: *const libc::c_char,
        _: ...
    ) -> libc::c_int;
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_auth {
    pub flags: libc::c_int,
    pub status: libc::c_int,
    pub name: *mut libc::c_char,
    pub data: *mut libc::c_void,
    pub init: Option<unsafe extern "C" fn(*mut passwd, *mut sudo_auth) -> libc::c_int>,
    pub setup: Option<
        unsafe extern "C" fn(*mut passwd, *mut *mut libc::c_char, *mut sudo_auth) -> libc::c_int,
    >,
    pub verify: Option<
        unsafe extern "C" fn(
            *mut passwd,
            *mut libc::c_char,
            *mut sudo_auth,
            *mut sudo_conv_callback,
        ) -> libc::c_int,
    >,
    pub approval: Option<unsafe extern "C" fn(*mut passwd, *mut sudo_auth, bool) -> libc::c_int>,
    pub cleanup: Option<unsafe extern "C" fn(*mut passwd, *mut sudo_auth) -> libc::c_int>,
    pub begin_session: Option<
        unsafe extern "C" fn(
            *mut passwd,
            *mut *mut *mut libc::c_char,
            *mut sudo_auth,
        ) -> libc::c_int,
    >,
    pub end_session: Option<unsafe extern "C" fn(*mut passwd, *mut sudo_auth) -> libc::c_int>,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct pam_message {
    pub msg_style: libc::c_int,
    pub msg: *const libc::c_char,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct pam_response {
    pub resp: *mut libc::c_char,
    pub resp_retcode: libc::c_int,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct pam_conv {
    pub conv: Option<
        unsafe extern "C" fn(
            libc::c_int,
            *mut *const pam_message,
            *mut *mut pam_response,
            *mut libc::c_void,
        ) -> libc::c_int,
    >,
    pub appdata_ptr: *mut libc::c_void,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_conv_callback {
    pub version: libc::c_uint,
    pub closure: *mut libc::c_void,
    pub on_suspend: sudo_conv_callback_fn_t,
    pub on_resume: sudo_conv_callback_fn_t,
}

pub type sudo_conv_callback_fn_t =
    Option<unsafe extern "C" fn(libc::c_int, *mut libc::c_void) -> libc::c_int>;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct conv_filter {
    pub msg: *mut libc::c_char,
    pub msglen: size_t,
}
static mut conv_callback: *mut sudo_conv_callback =
    0 as *const sudo_conv_callback as *mut sudo_conv_callback;
static mut pam_conv: pam_conv = unsafe {
    {
        pam_conv {
            conv: Some(
                converse
                    as unsafe extern "C" fn(
                        libc::c_int,
                        *mut *const pam_message,
                        *mut *mut pam_response,
                        *mut libc::c_void,
                    ) -> libc::c_int,
            ),
            appdata_ptr: &conv_callback as *const *mut sudo_conv_callback
                as *mut *mut sudo_conv_callback as *mut libc::c_void,
        }
        //init
    }
};
static mut def_prompt: *mut libc::c_char =
    b"[sudo] password for %p: \0" as *const u8 as *const libc::c_char as *mut libc::c_char;
static mut getpass_error: bool = false;
static mut pamh: *mut pam_handle_t = 0 as *const pam_handle_t as *mut pam_handle_t;
static mut conv_filter: *mut conv_filter = 0 as *const conv_filter as *mut conv_filter;

fn conv_filter_init() {
    unsafe {
        debug_decl!(SUDOERS_DEBUG_AUTH!());
        debug_return!();
    }
}

fn sudo_pam_strerror(
    mut handle: *mut pam_handle_t,
    mut errnum: libc::c_int,
) -> *const libc::c_char {
    let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
    static mut errbuf: [libc::c_char; 32] = [0; 32];

    unsafe {
        if errnum == PAM_SYSTEM_ERR as libc::c_int {
            return strerror(*__errno_location());
        }

        errstr = pam_strerror(handle, errnum);
        if errstr.is_null() {
            snprintf(
                errbuf.as_mut_ptr(),
                ::std::mem::size_of::<[libc::c_char; 32]>() as libc::c_ulong,
                b"PAM error %d\0" as *const u8 as *const libc::c_char,
                errnum,
            );
        }
    } //unsafe
    errstr
}

fn sudo_pam_init2(mut pw: *mut passwd, mut auth: *mut sudo_auth, mut quiet: bool) -> libc::c_int {
    static mut pam_status: libc::c_int = 0 as libc::c_int;
    unsafe {
        let mut tty_0: *const libc::c_char = sudo_user.ttypath;
        let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
        let mut pam_service: *const libc::c_char = std::ptr::null::<libc::c_char>();
        let mut rc: libc::c_int = 0;
        let sudo_debug_subsys_1: libc::c_int = *sudoers_subsystem_ids
            .as_mut_ptr()
            .offset(2 as libc::c_int as isize)
            as libc::c_int;
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        (*auth).data = &mut pam_status as *mut libc::c_int as *mut libc::c_void;

        pam_service = if sudo_mode & MODE_LOGIN_SHELL as libc::c_int != 0 {
            (*sudo_defs_table
                .as_mut_ptr()
                .offset(I_PAM_LOGIN_SERVICE as libc::c_int as isize))
            .sd_un
            .str_0
        } else {
            (*sudo_defs_table
                .as_mut_ptr()
                .offset(I_PAM_SERVICE as libc::c_int as isize))
            .sd_un
            .str_0
        };

        pam_status = pam_start(pam_service, (*pw).pw_name, &pam_conv, &mut pamh);
        if pam_status != PAM_SUCCESS as libc::c_int {
            errstr = sudo_pam_strerror(std::ptr::null_mut::<pam_handle_t>(), pam_status);

            sudo_debug_printf2_v1(
                get_function_name!(),
                get_file_name!(),
                line!() as libc::c_int,
                SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_1 as libc::c_int,
                b"pam_start(%s, %s, %p, %p): %s\0" as *const u8 as *const libc::c_char,
                pam_service,
                (*pw).pw_name,
                &mut pam_conv,
                &mut pamh,
                errstr,
            );

            if !quiet {
                log_warningx(
                    0 as libc::c_int,
                    b"unable to initialize PAM: %s\0" as *const u8 as *const libc::c_char,
                    errstr,
                );
            }
            debug_return_int!(AUTH_FATAL);
        }

        conv_filter_init();
        rc = pam_set_item(
            pamh,
            8 as libc::c_int,
            sudo_user.name as *const libc::c_void,
        );
        if rc != 0 as libc::c_int {
            errstr = sudo_pam_strerror(pamh, rc);
            sudo_debug_printf2_v1(
                get_function_name!(),
                get_file_name!(),
                line!() as libc::c_int,
                SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_1 as libc::c_int,
                b"pam_set_item(pamh, PAM_RUSER, %s): %s\0" as *const u8 as *const libc::c_char,
                sudo_user.name,
                errstr,
            );
        }

        if tty_0.is_null() {
            tty_0 = b"\0" as *const u8 as *const libc::c_char;
        }

        if !tty_0.is_null() {
            rc = pam_set_item(pamh, PAM_TTY as libc::c_int, tty_0 as *const libc::c_void);
            if rc != PAM_SUCCESS as libc::c_int {
                errstr = sudo_pam_strerror(pamh, rc);
                sudo_debug_printf2_v1(
                    get_function_name!(),
                    get_file_name!(),
                    line!() as libc::c_int,
                    SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_1 as libc::c_int,
                    b"pam_set_item(pamh, PAM_TTY, %s): %s\0" as *const u8 as *const libc::c_char,
                    tty_0,
                    errstr,
                );
            }
        }

        if (*sudo_defs_table
            .as_mut_ptr()
            .offset(I_PAM_SESSION as libc::c_int as isize))
        .sd_un
        .flag
            == 0
            && (*sudo_defs_table
                .as_mut_ptr()
                .offset(I_PAM_SETCRED as libc::c_int as isize))
            .sd_un
            .flag
                == 0
        {
            (*auth).end_session = None;
        }

        debug_return_int!(AUTH_SUCCESS);
    } //unsafe
}

#[no_mangle]
pub fn sudo_pam_init(mut pw: *mut passwd, mut auth: *mut sudo_auth) -> libc::c_int {
    sudo_pam_init2(pw, auth, 0 as libc::c_int != 0)
}

#[no_mangle]
pub fn sudo_pam_verify(
    mut pw: *mut passwd,
    mut prompt: *mut libc::c_char,
    mut auth: *mut sudo_auth,
    mut callback: *mut sudo_conv_callback,
) -> libc::c_int {
    let mut s: *const libc::c_char = std::ptr::null::<libc::c_char>();
    unsafe {
        let mut pam_status: *mut libc::c_int = (*auth).data as *mut libc::c_int;
        let sudo_debug_subsys_2: libc::c_int = *sudoers_subsystem_ids
            .as_mut_ptr()
            .offset(2 as libc::c_int as isize)
            as libc::c_int;
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        def_prompt = prompt;
        getpass_error = 0 as libc::c_int != 0;
        conv_callback = callback;

        *pam_status = pam_authenticate(pamh, PAM_SILENT as libc::c_uint as libc::c_int);

        if getpass_error {
            debug_return_int!(AUTH_INTR);
        }

        match *pam_status {
            PAM_SUCCESS => {
                debug_return_int!(AUTH_SUCCESS);
            }
            PAM_AUTH_ERR | PAM_AUTHINFO_UNAVAIL | PAM_MAXTRIES | PAM_PERM_DENIED => {
                sudo_debug_printf2_v1(
                    get_function_name!(),
                    get_file_name!(),
                    line!() as libc::c_int,
                    SUDO_DEBUG_WARN | SUDO_DEBUG_LINENO | sudo_debug_subsys_2 as libc::c_int,
                    b"pam_authenticate: %d\0" as *const u8 as *const libc::c_char,
                    *pam_status,
                );
                debug_return_int!(AUTH_FAILURE);
            }
            _ => {
                s = sudo_pam_strerror(pamh, *pam_status);
                log_warningx(
                    0 as libc::c_int,
                    b"PAM authentication error: %s\0" as *const u8 as *const libc::c_char,
                    s,
                );
                debug_return_int!(AUTH_FATAL);
            }
        }
    } //unsafe
}

#[no_mangle]
pub fn sudo_pam_approval(
    mut pw: *mut passwd,
    mut auth: *mut sudo_auth,
    mut exempt: bool,
) -> libc::c_int {
    let mut s: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut rc: libc::c_int = 0;
    let mut status: libc::c_int = AUTH_SUCCESS as libc::c_int;
    unsafe {
        let mut pam_status: *mut libc::c_int = (*auth).data as *mut libc::c_int;
        //let sudo_debug_subsys_3: libc::c_int = *sudoers_subsystem_ids
        //  .as_mut_ptr()
        //.offset(2 as libc::c_int as isize) as libc::c_int;
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        if (*sudo_defs_table
            .as_mut_ptr()
            .offset(I_PAM_ACCT_MGMT as libc::c_int as isize))
        .sd_un
        .flag
            != 0
        {
            rc = pam_acct_mgmt(pamh, PAM_SILENT as libc::c_uint as libc::c_int);
            match rc {
                PAM_SUCCESS => {}
                PAM_AUTH_ERR => {
                    log_warningx(
                        0 as libc::c_int,
                        b"account validation failure, is your account locked?\0" as *const u8
                            as *const libc::c_char,
                    );
                    status = AUTH_FATAL as libc::c_int;
                }
                PAM_NEW_AUTHTOK_REQD => {
                    if exempt {
                        rc = *pam_status;
                    } else {
                        log_warningx(
                            0 as libc::c_int,
                            b"Account or password is expired, reset your password and try again\0"
                                as *const u8 as *const libc::c_char,
                        );
                        rc = pam_chauthtok(
                            pamh,
                            PAM_CHANGE_EXPIRED_AUTHTOK as libc::c_uint as libc::c_int,
                        );
                        if rc != PAM_SUCCESS as libc::c_int {
                            s = pam_strerror(pamh, rc);
                            log_warningx(
                                0 as libc::c_int,
                                b"unable to change expired password: %s\0" as *const u8
                                    as *const libc::c_char,
                                s,
                            );
                            status = AUTH_FAILURE as libc::c_int;
                        }
                    }
                }
                PAM_AUTHTOK_EXPIRED => {
                    if exempt {
                        rc = *pam_status;
                    } else {
                        log_warningx(
                            0 as libc::c_int,
                            b"Password expired, contact your system administrator\0" as *const u8
                                as *const libc::c_char,
                        );
                        status = AUTH_FATAL as libc::c_int;
                    }
                }
                PAM_ACCT_EXPIRED => {
                    log_warningx(0 as libc::c_int,b"Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator\0" as *const u8 as *const libc::c_char,);
                    status = AUTH_FATAL as libc::c_int;
                }
                PAM_AUTHINFO_UNAVAIL | PAM_MAXTRIES | PAM_PERM_DENIED => {
                    s = sudo_pam_strerror(pamh, rc);
                    log_warningx(
                        0 as libc::c_int,
                        b"PAM account management error: %s\0" as *const u8 as *const libc::c_char,
                        s,
                    );
                    status = AUTH_FAILURE as libc::c_int;
                }
                _ => {
                    s = sudo_pam_strerror(pamh, rc);
                    log_warningx(
                        0 as libc::c_int,
                        b"PAM account management error: %s\0" as *const u8 as *const libc::c_char,
                        s,
                    );
                    status = AUTH_FATAL as libc::c_int;
                }
            } //end of match

            *pam_status = rc;
        }

        debug_return_int!(status);
    } //unsafe
}

#[no_mangle]
pub unsafe fn sudo_pam_cleanup(mut pw: *mut passwd, mut auth: *mut sudo_auth) -> libc::c_int {
    let mut pam_status: *mut libc::c_int = (*auth).data as *mut libc::c_int;
    debug_decl!(SUDOERS_DEBUG_AUTH!());
    //let sudo_debug_subsys_3: libc::c_int = *sudoers_subsystem_ids.as_mut_ptr().offset(2 as libc::c_int as isize) as libc::c_int;
    if *pam_status != PAM_SUCCESS as libc::c_int || ((*auth).end_session).is_none() {
        *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT as libc::c_int);
        pamh = std::ptr::null_mut::<pam_handle_t>();
    }
    debug_return_int!(if *pam_status == PAM_SUCCESS {
        AUTH_SUCCESS
    } else {
        AUTH_FAILURE
    });
}

#[no_mangle]
pub fn sudo_pam_begin_session(
    mut pw: *mut passwd,
    mut user_envp: *mut *mut *mut libc::c_char,
    mut auth: *mut sudo_auth,
) -> libc::c_int {
    let mut rc: libc::c_int = 0;
    let mut status: libc::c_int = 0 as libc::c_int;
    unsafe {
        let mut pam_status: *mut libc::c_int = (*auth).data as *mut libc::c_int;
        let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
        let sudo_debug_subsys_3: libc::c_int = *sudoers_subsystem_ids
            .as_mut_ptr()
            .offset(2 as libc::c_int as isize)
            as libc::c_int;
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        if pw.is_null() {
            if !pamh.is_null() {
                rc = pam_end(
                    pamh,
                    PAM_SUCCESS as libc::c_int | PAM_DATA_SILENT as libc::c_int,
                );
                if rc != PAM_SUCCESS as libc::c_int {
                    errstr = sudo_pam_strerror(pamh, rc);
                    sudo_debug_printf2_v1(
                        get_function_name!(),
                        get_file_name!(),
                        line!() as libc::c_int,
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_3 as libc::c_int,
                        b"pam_end: %s\0" as *const u8 as *const libc::c_char,
                        errstr,
                    );
                }
                pamh = std::ptr::null_mut::<pam_handle_t>();
            } //end of pamh.is_null
            debug_return_int!(status);
        }

        rc = pam_set_item(
            pamh,
            PAM_USER as libc::c_int,
            (*pw).pw_name as *const libc::c_void,
        );
        if rc != PAM_SUCCESS as libc::c_int {
            errstr = sudo_pam_strerror(pamh, rc);
            sudo_debug_printf2_v1(
                get_function_name!(),
                get_file_name!(),
                line!() as libc::c_int,
                SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_3 as libc::c_int,
                b"pam_set_item(pamh, PAM_USER, %s): %s\0" as *const u8 as *const libc::c_char,
                (*pw).pw_name,
                errstr,
            );
        }

        if (*sudo_defs_table
            .as_mut_ptr()
            .offset(I_PAM_SETCRED as libc::c_int as isize))
        .sd_un
        .flag
            != 0
        {
            rc = pam_setcred(pamh, PAM_REINITIALIZE_CRED as libc::c_uint as libc::c_int);
            if rc != PAM_SUCCESS as libc::c_int {
                errstr = sudo_pam_strerror(pamh, rc);
                sudo_debug_printf2_v1(
                    get_function_name!(),
                    get_file_name!(),
                    line!() as libc::c_int,
                    SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_3 as libc::c_int,
                    b"pam_setcred: %s\0" as *const u8 as *const libc::c_char,
                    errstr,
                );
            }
        }

        if (*sudo_defs_table
            .as_mut_ptr()
            .offset(I_PAM_SESSION as libc::c_int as isize))
        .sd_un
        .flag
            != 0
        {
            let silent: bool =
                sudo_mode & (MODE_SHELL as libc::c_int | MODE_LOGIN_SHELL as libc::c_int) == 0;
            rc = pam_open_session(
                pamh,
                (if silent as libc::c_int != 0 {
                    PAM_SILENT as libc::c_uint
                } else {
                    0 as libc::c_int as libc::c_uint
                }) as libc::c_int,
            );

            match rc {
                PAM_SUCCESS => {}
                PAM_SESSION_ERR => {
                    errstr = sudo_pam_strerror(pamh, rc);
                    sudo_debug_printf2_v1(
                        get_function_name!(),
                        get_file_name!(),
                        line!() as libc::c_int,
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_3 as libc::c_int,
                        b"pam_open_session: %s\0" as *const u8 as *const libc::c_char,
                        errstr,
                    );
                    (*sudo_defs_table
                        .as_mut_ptr()
                        .offset(I_PAM_SESSION as libc::c_int as isize))
                    .sd_un
                    .flag = 0 as libc::c_int;
                }
                _ => {
                    *pam_status = rc;
                    errstr = sudo_pam_strerror(pamh, rc);
                    log_warningx(
                        0 as libc::c_int,
                        b"%s: %s\0" as *const u8 as *const libc::c_char,
                        b"pam_open_session\0" as *const u8 as *const libc::c_char,
                        errstr,
                    );
                    rc = pam_end(pamh, *pam_status | PAM_DATA_SILENT as libc::c_int);
                    if rc != PAM_SUCCESS as libc::c_int {
                        errstr = sudo_pam_strerror(pamh, rc);
                        sudo_debug_printf2_v1(
                            get_function_name!(),
                            get_file_name!(),
                            line!() as libc::c_int,
                            SUDO_DEBUG_ERROR
                                | SUDO_DEBUG_LINENO
                                | sudo_debug_subsys_3 as libc::c_int,
                            b"pam_end: %s\0" as *const u8 as *const libc::c_char,
                            errstr,
                        );
                    }
                    pamh = std::ptr::null_mut::<pam_handle_t>();
                    status = AUTH_FATAL as libc::c_int;
                    debug_return_int!(status);
                }
            }
        }

        if !user_envp.is_null() {
            let mut pam_envp: *mut *mut libc::c_char = pam_getenvlist(pamh);
            if !pam_envp.is_null() {
                if !env_init(*user_envp as *const *mut libc::c_char)
                    || !env_merge(pam_envp as *const *mut libc::c_char)
                {
                    status = AUTH_FATAL as libc::c_int;
                }
                *user_envp = env_get();
                env_init(std::ptr::null::<*mut libc::c_char>());
                free(pam_envp as *mut libc::c_void);
            }
        }

        debug_return_int!(status);
    } //unsafe
}

#[no_mangle]
pub fn sudo_pam_end_session(mut pw: *mut passwd, mut auth: *mut sudo_auth) -> libc::c_int {
    let mut rc: libc::c_int = 0;
    let mut status: libc::c_int = 0 as libc::c_int;
    let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
    unsafe {
        let sudo_debug_subsys_4: libc::c_int = *sudoers_subsystem_ids
            .as_mut_ptr()
            .offset(2 as libc::c_int as isize)
            as libc::c_int;
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        if !pamh.is_null() {
            rc = pam_set_item(
                pamh,
                PAM_USER as libc::c_int,
                (*pw).pw_name as *const libc::c_void,
            );
            if rc != PAM_SUCCESS as libc::c_int {
                errstr = sudo_pam_strerror(pamh, rc);
                sudo_debug_printf2_v1(
                    get_function_name!(),
                    get_file_name!(),
                    line!() as libc::c_int,
                    SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_4 as libc::c_int,
                    b"pam_set_item(pamh, PAM_USER, %s): %s\0" as *const u8 as *const libc::c_char,
                    (*pw).pw_name,
                    errstr,
                );
            }

            if (*sudo_defs_table
                .as_mut_ptr()
                .offset(I_PAM_SESSION as libc::c_int as isize))
            .sd_un
            .flag
                != 0
            {
                rc = pam_close_session(pamh, PAM_SILENT as libc::c_uint as libc::c_int);
                if rc != PAM_SUCCESS as libc::c_int {
                    errstr = sudo_pam_strerror(pamh, rc);
                    sudo_debug_printf2_v1(
                        get_function_name!(),
                        get_file_name!(),
                        line!() as libc::c_int,
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_4 as libc::c_int,
                        b"pam_close_session: %s\0" as *const u8 as *const libc::c_char,
                        errstr,
                    );
                }
            }

            if (*sudo_defs_table
                .as_mut_ptr()
                .offset(I_PAM_SETCRED as libc::c_int as isize))
            .sd_un
            .flag
                != 0
            {
                rc = pam_setcred(
                    pamh,
                    (PAM_DELETE_CRED as libc::c_uint | PAM_SILENT as libc::c_uint) as libc::c_int,
                );
                if rc != PAM_SUCCESS as libc::c_int {
                    errstr = sudo_pam_strerror(pamh, rc);
                    sudo_debug_printf2_v1(
                        get_function_name!(),
                        get_file_name!(),
                        line!() as libc::c_int,
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_4 as libc::c_int,
                        b"pam_setcred: %s\0" as *const u8 as *const libc::c_char,
                        errstr,
                    );
                }
            }

            rc = pam_end(
                pamh,
                PAM_SUCCESS as libc::c_int | PAM_DATA_SILENT as libc::c_int,
            );
            if rc != PAM_SUCCESS as libc::c_int {
                errstr = sudo_pam_strerror(pamh, rc);
                sudo_debug_printf2_v1(
                    get_function_name!(),
                    get_file_name!(),
                    line!() as libc::c_int,
                    SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_4 as libc::c_int,
                    b"pam_end: %s\0" as *const u8 as *const libc::c_char,
                    errstr,
                );
                status = AUTH_FATAL as libc::c_int;
            }

            pamh = std::ptr::null_mut::<pam_handle_t>();
        }

        debug_return_int!(status);
    } //unsafe
}

fn use_pam_prompt(mut pam_prompt: *const libc::c_char) -> bool {
    let mut user_len: size_t = 0;
    //let sudo_debug_subsys_5: libc::c_int = *sudoers_subsystem_ids.as_mut_ptr().offset(2 as libc::c_int as isize) as libc::c_int;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        if (*sudo_defs_table
            .as_mut_ptr()
            .offset(I_PASSPROMPT_OVERRIDE as libc::c_int as isize))
        .sd_un
        .flag
            != 0
        {
            debug_return_bool!(false);
        }

        if strncmp(
            def_prompt,
            b"Password:\0" as *const u8 as *const libc::c_char,
            9 as libc::c_int as libc::c_ulong,
        ) == 0 as libc::c_int
            && (*def_prompt.offset(9 as libc::c_int as isize) as libc::c_int == '\u{0}' as i32
                || *def_prompt.offset(9 as libc::c_int as isize) as libc::c_int == ' ' as i32
                    && *def_prompt.offset(10 as libc::c_int as isize) as libc::c_int
                        == '\u{0}' as i32)
        {
            debug_return_bool!(true);
        }

        if strcmp(
            pam_prompt,
            dcgettext(
                b"Linux-PAM\0" as *const u8 as *const libc::c_char,
                b"Password:\0" as *const u8 as *const libc::c_char,
                5 as libc::c_int,
            ),
        ) == 0 as libc::c_int
            || strcmp(
                pam_prompt,
                dcgettext(
                    b"Linux-PAM\0" as *const u8 as *const libc::c_char,
                    b"Password: \0" as *const u8 as *const libc::c_char,
                    5 as libc::c_int,
                ),
            ) == 0 as libc::c_int
            || strncmp(
                pam_prompt,
                b"Password:\0" as *const u8 as *const libc::c_char,
                9 as libc::c_int as libc::c_ulong,
            ) == 0 as libc::c_int
                && (*pam_prompt.offset(9 as libc::c_int as isize) as libc::c_int == '\u{0}' as i32
                    || *pam_prompt.offset(9 as libc::c_int as isize) as libc::c_int == ' ' as i32
                        && *pam_prompt.offset(10 as libc::c_int as isize) as libc::c_int
                            == '\u{0}' as i32)
        {
            debug_return_bool!(false);
        }

        user_len = strlen(sudo_user.name);
        if strncmp(pam_prompt, sudo_user.name, user_len) == 0 as libc::c_int {
            let mut cp: *const libc::c_char = pam_prompt.offset(user_len as isize);
            if strncmp(
                cp,
                b"'s Password:\0" as *const u8 as *const libc::c_char,
                12 as libc::c_int as libc::c_ulong,
            ) == 0 as libc::c_int
                && (*cp.offset(12 as libc::c_int as isize) as libc::c_int == '\u{0}' as i32
                    || *cp.offset(12 as libc::c_int as isize) as libc::c_int == ' ' as i32
                        && *cp.offset(13 as libc::c_int as isize) as libc::c_int == '\u{0}' as i32)
            {
                debug_return_bool!(false);
            }
        }
        debug_return_bool!(true);
    } //unsafe
}

#[no_mangle]
fn is_filtered(mut msg: *const libc::c_char) -> bool {
    let mut filtered: bool = 0 as libc::c_int != 0;
    unsafe {
        if !conv_filter.is_null() {
            let mut filt: *mut conv_filter = conv_filter;
            while !((*filt).msg).is_null() {
                if strncmp(msg, (*filt).msg, (*filt).msglen) == 0 as libc::c_int {
                    filtered = 1 as libc::c_int != 0;
                    break;
                } else {
                    filt = filt.offset(1);
                }
            }
        }
    } //unsafe
    filtered
}

unsafe extern "C" fn converse(
    mut num_msg: libc::c_int,
    mut msg: *mut *const pam_message,
    mut reply_out: *mut *mut pam_response,
    mut vcallback: *mut libc::c_void,
) -> libc::c_int {
    let mut callback: *mut sudo_conv_callback = std::ptr::null_mut::<sudo_conv_callback>();
    let mut reply: *mut pam_response = std::ptr::null_mut::<pam_response>();
    let mut prompt: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut pass: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut n: libc::c_int = 0;
    let mut type_0: libc::c_int = 0;
    let mut ret: libc::c_int = 0 as libc::c_int;
    let sudo_debug_subsys_5: libc::c_int = *sudoers_subsystem_ids
        .as_mut_ptr()
        .offset(2 as libc::c_int as isize)
        as libc::c_int;
    debug_decl!(SUDOERS_DEBUG_AUTH!());

    if num_msg <= 0 as libc::c_int || num_msg > PAM_MAX_NUM_MSG as libc::c_int {
        sudo_debug_printf2_v1(
            get_function_name!(),
            get_file_name!(),
            line!() as libc::c_int,
            SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_5 as libc::c_int,
            b"invalid number of PAM messages: %d\0" as *const u8 as *const libc::c_char,
            num_msg,
        );
        debug_return_int!(PAM_CONV_ERR);
    }

    sudo_debug_printf2_v1(
        get_function_name!(),
        get_file_name!(),
        line!() as libc::c_int,
        SUDO_DEBUG_DEBUG | SUDO_DEBUG_LINENO | sudo_debug_subsys_5 as libc::c_int,
        b"number of PAM messages: %d\0" as *const u8 as *const libc::c_char,
        num_msg,
    );

    reply = calloc(
        num_msg as libc::c_ulong,
        ::std::mem::size_of::<pam_response>() as libc::c_ulong,
    ) as *mut pam_response;
    if reply.is_null() {
        sudo_warnx!(
            b"%s: %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            b"unable to allocate memory\0" as *const u8 as *const libc::c_char
        );
        debug_return_int!(PAM_BUF_ERR);
    }
    *reply_out = reply;

    if !vcallback.is_null() {
        callback = *(vcallback as *mut *mut sudo_conv_callback);
    }

    // goto done
    'done: loop {
        n = 0 as libc::c_int;
        while n < num_msg {
            let mut pm: *const pam_message = *msg.offset(n as isize);
            type_0 = SUDO_CONV_PROMPT_ECHO_OFF as libc::c_int;
            match (*pm).msg_style {
                PAM_PROMPT_ECHO_ON | PAM_PROMPT_ECHO_OFF => {
                    if (*pm).msg_style == PAM_PROMPT_ECHO_ON {
                        type_0 = SUDO_CONV_PROMPT_ECHO_ON;
                    }
                    if getpass_error {
                        break 'done;
                    }

                    prompt = if use_pam_prompt((*pm).msg) as libc::c_int != 0 {
                        (*pm).msg
                    } else {
                        def_prompt
                    };
                    pass = auth_getpass(prompt, type_0, callback);
                    if pass.is_null() {
                        getpass_error = true as libc::c_int != 0;
                        ret = PAM_CONV_ERR as libc::c_int;
                        break 'done;
                    }
                    if strlen(pass) >= PAM_MAX_RESP_SIZE as libc::c_int as libc::c_ulong {
                        sudo_debug_printf2_v1(
                            get_function_name!(),
                            get_file_name!(),
                            line!() as libc::c_int,
                            SUDO_DEBUG_ERROR
                                | SUDO_DEBUG_LINENO
                                | sudo_debug_subsys_5 as libc::c_int,
                            b"password longer than %d\0" as *const u8 as *const libc::c_char,
                            PAM_MAX_RESP_SIZE,
                        );
                        ret = PAM_CONV_ERR as libc::c_int;
                        sudo_memset_s(
                            pass as *mut libc::c_void,
                            SUDO_CONV_REPL_MAX as libc::c_int as size_t,
                            0 as libc::c_int,
                            strlen(pass),
                        );
                        break 'done;
                    }
                    (*reply.offset(n as isize)).resp = pass;
                }

                PAM_TEXT_INFO => {
                    if !((*pm).msg).is_null() && !is_filtered((*pm).msg) {
                        sudo_debug_printf2_v1(
                            get_function_name!(),
                            get_file_name!(),
                            line!() as libc::c_int,
                            SUDO_CONV_INFO_MSG
                                | SUDO_CONV_PREFER_TTY
                                | sudo_debug_subsys_5 as libc::c_int,
                            b"%s\0" as *const u8 as *const libc::c_char,
                            (*pm).msg,
                        );
                    }
                }

                PAM_ERROR_MSG => {
                    if !((*pm).msg).is_null() {
                        sudo_debug_printf2_v1(
                            get_function_name!(),
                            get_file_name!(),
                            line!() as libc::c_int,
                            SUDO_CONV_ERROR_MSG
                                | SUDO_CONV_PREFER_TTY
                                | sudo_debug_subsys_5 as libc::c_int,
                            b"%s\0" as *const u8 as *const libc::c_char,
                            (*pm).msg,
                        );
                    }
                }

                _ => {
                    sudo_debug_printf2_v1(
                        get_function_name!(),
                        get_file_name!(),
                        line!() as libc::c_int,
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO | sudo_debug_subsys_5 as libc::c_int,
                        b"unsupported message style: %d\0" as *const u8 as *const libc::c_char,
                        (*pm).msg_style,
                    );
                    ret = PAM_CONV_ERR;
                    break 'done;
                }
            }
            n += 1;
        } //end of while

        break 'done;
    } //end of done

    if ret != PAM_SUCCESS {
        n = 0 as libc::c_int;
        while n < num_msg {
            let mut pr: *mut pam_response = &mut *reply.offset(n as isize) as *mut pam_response;
            if !((*pr).resp).is_null() {
                sudo_memset_s(
                    (*pr).resp as *mut libc::c_void,
                    255 as libc::c_int as size_t,
                    0 as libc::c_int,
                    strlen((*pr).resp),
                );
                free((*pr).resp as *mut libc::c_void);
                (*pr).resp = std::ptr::null_mut::<libc::c_char>();
            }
            n += 1;
        }
        free(reply as *mut libc::c_void);
        *reply_out = std::ptr::null_mut::<pam_response>();
    }
    debug_return_int!(ret);
}
